#ifndef USER_PLUGIN_DUMMY
#define USER_PLUGIN_DUMMY
#include <iostream>
#include <string>
#include <map>
#include <stdio.h>
#include <stdlib.h>
#include "../../../libpland/lib/plugin.hpp"

#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>

#include <vorbis/codec.h>
#include <vorbis/vorbisfile.h>

#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <stdio.h>
#include <linux/soundcard.h>

#define PORT 9000
#define HOST "stream-tx4.radioparadise.com"
#define HANDSHAKE "GET /rp_96.ogg HTTP/1.1\nHost: stream-tx4.radioparadise.com\n\n"


using namespace std;

static size_t ovcb_read(void *ptr, size_t size, size_t nmemb, void *datasource);
static int    ovcb_close(void *datasource);


ov_callbacks vorbis_callbacks = {
	ovcb_read,
	NULL,
	ovcb_close,
	NULL
};

static size_t ovcb_read(void *ptr, size_t size, size_t nmemb, void *datasource)
{
	int sockfd = (long long int)datasource;
	size_t ret;
	ret = recv(sockfd, ptr, size*nmemb, 0);
	return ret;
}

static int ovcb_close(void *datasource)
{
	int sockfd = (long long int)datasource;
	return close(sockfd);
}

class UserC_Ogg : public UserC_Plugin
{
public:
	UserC_Ogg();
	~UserC_Ogg();
	void start();
	void stop();
	void load_queues(CoreC_DQueue * front ,CoreC_DQueue * back);
private:
	CoreC_DQueue *_front;
	CoreC_DQueue *_back;
	bool _running;

};

#endif


UserC_Ogg::UserC_Ogg()
{
	_running = false;
}

void UserC_Ogg::start()
{
	_running = true;
	OggVorbis_File file;

	//Get the socket ready
	int sockfd;
	int ret;
	struct sockaddr_in serv_addr;
	struct hostent *server;
	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	server = gethostbyname(HOST);
	bzero((char *) &serv_addr, sizeof(serv_addr));
	serv_addr.sin_family = AF_INET;
	bcopy((char *)server->h_addr,
		  (char *)&serv_addr.sin_addr.s_addr,
		  server->h_length);
	serv_addr.sin_port = htons(PORT);
	connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr));
	std::string shake(HANDSHAKE);
	ret =  write(sockfd, shake.c_str(), shake.size());
	char l = 0;
	while(true)
	{
		read(sockfd, &l, 1);
		if(l == '\n')
		{
			read(sockfd, &l, 1);
			if(l == '\r')
			{
				read(sockfd, &l, 1);
				if(l == '\n')
					break;
			}
		}
	}


	//Get the Decoder setup
	ov_open_callbacks((void*)((long long int)sockfd),&file,NULL,-1,vorbis_callbacks);

	CoreC_Settings* set = CoreC_Settings::Instance();
	vorbis_info *vi=ov_info(&file,0);;
	set->setSetting("stream.bitrate", utill_to_string(vi->rate));
	set->setSetting("stream.channels", utill_to_string(vi->channels));
	set->setSetting("stream.depth", utill_to_string(16));
	int current_section = 0;
	CoreC_Data * pcm = NULL;
	CoreC_Data_Header* header;
	char *buff;
	int n;

	while(_running)
	{
		buff = new char[4096];
		n = ov_read(&file, buff, 4096,0,2,1,&current_section);
		if(n<0)
		{
			delete[] buff;
			continue;
		}
		header = new CoreC_Data_Header;
		header->_size = n;
		header->_tag = 1;
		pcm = new CoreC_Data(buff, header);
		_back->push(pcm);
	}
}

void UserC_Ogg::stop()
{
	_running = false;

}

void UserC_Ogg::load_queues(CoreC_DQueue* front ,CoreC_DQueue* back)
{
	_front  = front;
	_back  = back;
}


extern "C"
{
	UserC_Plugin* Core_GetInstance()
	{
		return new UserC_Ogg();
	}

	void Core_KillInstance(UserC_Plugin* a)
	{
		delete a;
	}
}
